<?php

namespace pmvc\data\sql\sqlite;

use pmvc\data\sql\AbstractDataSource;
use pmvc\util\StringUtil;
use Exception;

class SQLiteDataSource 
	extends AbstractDataSource {

	public $filename;
	public $mode;
	public $usePersistentResource = false;
	
	private $link = false;

	public function createTransaction() {
		return new SQLiteTransaction($this);
	}

	public function connect() {
		if ($this->link!==false) {
			return;
		}
		if (empty($this->filename)) {
			throw new Exception("Database filename not specified");
		}
		if (empty($this->mode)) {
			$this->mode = "0666";
		}
		$errorMessage = "";
		$this->link = ($this->usePersistentResource===true)
			? sqlite_popen($this->filename, intval($this->mode), $errorMessage)
			: sqlite_open($this->filename, intval($this->mode), $errorMessage);
	
		$this->assert($this->link!==false, "Opening database failed: ".$errorMessage);
	}
	
	public function escape($str) {
		return sqlite_escape_string($str);
	}
	
	public function query() {
		$a		= func_get_args();
        $sql 	= array_shift($a);
        $sql 	= $this->buildQuery($sql, $a);
        \pmvc\log\Log::trace(__CLASS__, "Executing query: {0}", $sql);
        $ret = sqlite_query($this->link, $sql, SQLITE_BOTH);
        $this->assert($ret!==false, "Query failed");
        return $ret;
	}
	
	public function update() {
		return call_user_func_array(array($this,"query"), func_get_args());
	}
	
	public function lastInsertId() {
		$ret = sqlite_last_insert_rowid($this->link);
		$this->assert($ret!==false, "Getting insert id failed");
        return $ret;
	}
	
	public function numberOfRows($res) {
		$ret = sqlite_num_rows($res);
		$this->assert($ret!==false, "Getting number of rows failed");
        return $ret;
	}
	
	public function fetchRowObject($res) {
		return sqlite_fetch_object($res);
	}
	
	public function numberOfAffectedRows($res) {
		return sqlite_changes($res);
	}
	
	public function freeResult($res) {
		// no-op
		return true;
	}

	public function getLastError() {
		$lastError = sqlite_last_error($this->link);
		$message = sqlite_error_string($lastError);
		return "errno ".$lastError." - ".$message;
	}

	private function assert($value, $message="") {
		if ($value!==true) {
			throw $this->createExceptionFromLastError($message);
		}
	}

	private function createExceptionFromLastError($message="", $previous=null) {
		$lastError = sqlite_last_error($this->link);
		$message = ($lastError!=0) ? sqlite_error_string($lastError) : "";
		return new Exception($message, $lastError, $previous);
	}

}

?>